//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include<ddk.h>
#include <bulverde.h>

#define OSTR_BASE   0x40A00000
#define OSSR_M4     (1 << 4)    /* Match status channel 4 */
#define OSSR_M5     (1 << 5)    /* Match status channel 5 */
#define OSSR_M6     (1 << 6)    /* Match status channel 6 */
#define OSSR_M7     (1 << 7)    /* Match status channel 7 */

#define OIER_E4     (1 << 4)    /* Interrupt enable channel 4 */
#define OIER_E5     (1 << 5)    /* Interrupt enable channel 5 */
#define OIER_E6     (1 << 6)    /* Interrupt enable channel 6 */
#define OIER_E7     (1 << 7)    /* Interrupt enable channel 7 */

#define REG(x)    (*(volatile unsigned long*)(((x)+ 0x40000000)))
void CDECL DrvTimerIsr( irq_t irq, void *pvDevice, InterruptContext *pContext)
{
    unsigned long status = OSSR;
    //clear timer interrupt
    OSSR = OSSR_M4 | OSSR_M5 | OSSR_M6 | OSSR_M7;

    if(status&OSSR_M4) {
        NotifyByIsr(EVENT_TIMER0,0,NULL);
    }
    if(status&OSSR_M5) {
        NotifyByIsr(EVENT_TIMER1,0,NULL);
    }
    if(status&OSSR_M6) {
        NotifyByIsr(EVENT_TIMER2,0,NULL);
    }
    if(status&OSSR_M7) {
        NotifyByIsr(EVENT_TIMER3,0,NULL);
    }
}

void initialize()
{
    REG(OSTR_BASE+OMCR4_OFFSET) = 0x000000ca;//ms
    REG(OSTR_BASE+OMCR5_OFFSET) = 0x000000c9;//1/32768s
    REG(OSTR_BASE+OMCR6_OFFSET) = 0x000000cb;//s
    REG(OSTR_BASE+OMCR7_OFFSET) = 0x000000cb;//s

    REG(OSTR_BASE+OSMR4_OFFSET)=0x000000010;//1 s
    REG(OSTR_BASE+OSMR5_OFFSET)=32768;//1 s
    REG(OSTR_BASE+OSMR6_OFFSET)=0x0000003c;//1 min
    REG(OSTR_BASE+OSMR7_OFFSET)=0x00000e10;//1 hour

    REG(0x40a0001c)|=0x000000f0;//enable channel 4-7

    DzRegisterIsr(7/*OST_4_11*/, IPL30, (isr_t)DrvTimerIsr, NULL);
}

void dumpreg()
{
    cprintf("OIER %x\n",REG(0x40a0001c));
    cprintf("for channel 4\n");
    cprintf("OMCR4 %x\n",REG(OSTR_BASE+OMCR4_OFFSET));
    cprintf("OSMR4 %x\n",REG(OSTR_BASE+OSMR4_OFFSET));
    cprintf("OSCR4 %x\n",REG(OSTR_BASE+OSCR4_OFFSET));
    cprintf("for channel 5\n");
    cprintf("OMCR5 %x\n",REG(OSTR_BASE+OMCR5_OFFSET));
    cprintf("OSMR5 %x\n",REG(OSTR_BASE+OSMR5_OFFSET));
    cprintf("OSCR5 %x\n",REG(OSTR_BASE+OSCR5_OFFSET));
    cprintf("for channel 6\n");
    cprintf("OMCR6 %x\n",REG(OSTR_BASE+OMCR6_OFFSET));
    cprintf("OSMR6 %x\n",REG(OSTR_BASE+OSMR6_OFFSET));
    cprintf("OSCR6 %x\n",REG(OSTR_BASE+OSCR6_OFFSET));
    cprintf("for channel 7\n");
    cprintf("OMCR7 %x\n",REG(OSTR_BASE+OMCR7_OFFSET));
    cprintf("OSMR7 %x\n",REG(OSTR_BASE+OSMR7_OFFSET));
    cprintf("OSCR7 %x\n",REG(OSTR_BASE+OSCR7_OFFSET));
}
void start0()
{
    OIER|=OIER_E4;
    REG(OSTR_BASE+OSCR4_OFFSET)=0;//start to count.
}
void start1()
{
    OIER|=OIER_E5;
    REG(OSTR_BASE+OSCR5_OFFSET)=0;//start to count.
}
void start2()
{
    OIER|=OIER_E6;
    REG(OSTR_BASE+OSCR6_OFFSET)=0;//start to count.
}
void start3()
{
    OIER|=OIER_E7;
    REG(OSTR_BASE+OSCR7_OFFSET)=0;//start to count.
}

void stop0()
{
    OIER&=~OIER_E4;
}
void stop1()
{
    OIER&=~OIER_E5;
}
void stop2()
{
    OIER&=~OIER_E6;
}
void stop3()
{
    OIER&=~OIER_E7;
}

void setWatchDog(int mSec)
{
    OWER|=0x01;
    OSMR3 = OSCR+mSec*3250;
}
